package gui;

import gui.MyTC.OperationAction;

import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.util.List;

import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JMenuItem;
import javax.swing.JToolBar;
import javax.swing.KeyStroke;

import org.apache.log4j.Logger;

import logic.configuration.CommandSpec;
import logic.configuration.Configuration;
import logic.configuration.MenuCommands;
import logic.operation.AbstractFileOperation;
import logic.operation.IFileOperation;

public class Configurator {
	
	Logger logger = Logger.getLogger(Configurator.class.getName());
	
	//Configuration configuration;
	MyTC mainWindow;
	
	//obiekt konfiguraracji nie powinien byc dekapsulowany
	List<CommandSpec> commandSpecs;
	List<String> toolbarCommands;
	MenuCommands menuCommands;
	
	public Configurator(Configuration configuration, MyTC mainWindow) {
		this.commandSpecs = configuration.getCommandSpec();
		this.toolbarCommands = configuration.getToolbarCommands();
		this.menuCommands = configuration.getMenuCommands();
		this.mainWindow = mainWindow;
	}
	
	//TODO akcje i buttony dodawane tutaj dynamicznie
	//TODO liczbe buttonow i opcji w menu takze mozna uzaleznic od zawartosci xmla
	public void configure() throws ClassNotFoundException, InstantiationException, IllegalAccessException {
		
		
		//TODO narazie powienien być toolbars
		JToolBar toolBar = mainWindow.getToolBar();
		
		CommandSpec spec = null;
		ClassLoader loader = Configurator.class.getClassLoader();
		logger.info("SIZE:"+toolbarCommands.size());
		for (int i = 0; i < toolbarCommands.size(); i++) {
			spec = getCommandSpecById(toolbarCommands.get(i));		//foreach
			
			JButton button = new JButton();
			toolBar.add(button);
			
			//currentButton = toolbarButtons.get(i);
				
			logger.info(button + " " + i);
			logger.info(spec.getHint());
			button.setToolTipText(spec.getHint());
			loader.loadClass(spec.getHandlerClass());
			//?
			@SuppressWarnings("unchecked")
			Class<? extends IFileOperation> operationClass = (Class<? extends IFileOperation>) loader.loadClass(spec.getHandlerClass());
			//TODO zamiast operationClass.newInstance() ustawienie w OperationAction instancji klasy operacji jaka ma być tworzona przy wywoływaniu akcji
			OperationAction action = mainWindow.new OperationAction(operationClass.newInstance());
			
			//skróty klawiaturowe dla tabeli
			mainWindow.getTable(0).getInputMap().put(KeyStroke.getKeyStroke(adjustKeyString(spec.getKey())), spec.getName());
			mainWindow.getTable(0).getActionMap().put(spec.getName(), action);
			
			mainWindow.getTable(1).getInputMap().put(KeyStroke.getKeyStroke(adjustKeyString(spec.getKey())), spec.getName());
			mainWindow.getTable(1).getActionMap().put(spec.getName(), action);
			
			//skróty klawiaturowe dla listy
			mainWindow.getList(0).getInputMap().put(KeyStroke.getKeyStroke(adjustKeyString(spec.getKey())), spec.getName());
			mainWindow.getList(0).getActionMap().put(spec.getName(), action);
			
			mainWindow.getList(1).getInputMap().put(KeyStroke.getKeyStroke(adjustKeyString(spec.getKey())), spec.getName());
			mainWindow.getList(1).getActionMap().put(spec.getName(), action);
			
			button.addActionListener(action);
			
			//zalozenie że mamy tylko jeden listener na kazdym buttonie
			//mozna takze wywolywac odpowiednie konstruktory wyciągnięte też przez refleksję
			//może to pozwolić na uniknięcie konieczności rzutowania
			//TODO w wersji finalnej tutaj powinien być tworzony obiekt Listenera 
			//a poniższe przekazywane do jego kontruktora
			//((AbstractFileOperationAction) currentButton.getActionListeners()[0])
			//		.setOperation((IFileOperation) operationClass.newInstance());
			
			button.setIcon(new ImageIcon(spec.getIcon()));
		}
		JMenuItem menuItem = null;
		//konfiguracja menu File
		for (String mcf : menuCommands.getFileMenuCommands()) {
			spec = getCommandSpecById(mcf);
			menuItem = new JMenuItem(spec.getName());
			menuItem.setToolTipText(spec.getHint());
			menuItem.setIcon(new ImageIcon(spec.getIcon()));
			mainWindow.getFileMenu().add(menuItem);
			
			loader.loadClass(spec.getHandlerClass());
			//?
			@SuppressWarnings("unchecked")
			Class<? extends IFileOperation> operationClass = (Class<? extends IFileOperation>) loader.loadClass(spec.getHandlerClass());
			menuItem.addActionListener(mainWindow.new OperationAction(operationClass.newInstance()));
		}
		
		//konfiguracja menu Edit
		//TODO DRY - do funkcji
		for (String mce : menuCommands.getEditMenuCommands()) {
			spec = getCommandSpecById(mce);
			menuItem = new JMenuItem(spec.getName());
			menuItem.setToolTipText(spec.getHint());
			menuItem.setIcon(new ImageIcon(spec.getIcon()));
			mainWindow.getEditMenu().add(menuItem);
			
			loader.loadClass(spec.getHandlerClass());
			//?
			@SuppressWarnings("unchecked")
			Class<? extends IFileOperation> operationClass = (Class<? extends IFileOperation>) loader.loadClass(spec.getHandlerClass());
			menuItem.addActionListener(mainWindow.new OperationAction(operationClass.newInstance()));
		}
	}
	
	private CommandSpec getCommandSpecById(String id) {
		
		for (CommandSpec cs : commandSpecs) {
			if (cs.getId().equals(id)) {
				return cs;
			}
		}
		
		return null;
	}
	
	//metoda uproszczona, działająca źle w przypadku ogólnym
	//TODO metoda pelna wymaga parsowania stringa i dopiero zmian na tokenach
	private String adjustKeyString(String s) {
		s = s.replace('+', ' ');
		s = s.replace("Ctrl", "ctrl");
		s = s.replace("Delete", "DELETE");
		return s;
	}

}
